﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Threading;

namespace Apq.Net
{
	/// <summary>
	/// Apq.Net.HttpWebRequest
	/// </summary>
	public class HttpWebRequest
	{
		// 从远程流中每次读取的字节数(单位:B)
		private int _ReadSize = 8192;

		/// <summary>
		/// 默认构造函数,为成员赋予默认值
		/// </summary>
		public HttpWebRequest()
		{
		}

		/// <summary>
		/// 以指定编码发送请求到一 Url
		/// </summary>
		/// <param name="eEncoding">编码</param>
		/// <param name="Url"></param>
		/// <param name="inData">内容</param>
		/// <param name="Method">GET 或 POST</param>
		/// <param name="cc"></param>
		/// <param name="ContentType"></param>
		/// <param name="Referer">来源页</param>
		/// <returns></returns>
		public string Request(Encoding eEncoding, string Url, string inData, string Method, CookieContainer cc, string ContentType, string Referer = "")
		{
			string outdata = "";
			System.Net.HttpWebRequest hwRequest = (System.Net.HttpWebRequest)WebRequest.Create(Url);
			hwRequest.ContentType = ContentType;// "application/x-www-form-urlencoded";
			//hwRequest.ContentLength = eEncoding.GetBytes(inData).Length;
			hwRequest.Method = Method;// "POST";
			hwRequest.CookieContainer = cc;
			if (!string.IsNullOrWhiteSpace(Referer)) hwRequest.Referer = Referer;
			Stream hwrStream = hwRequest.GetRequestStream();
			StreamWriter sw = new StreamWriter(hwrStream, eEncoding);//Encoding.GetEncoding("gb2312"));
			sw.Write(inData);
			sw.Flush();
			sw.Close();
			hwrStream.Flush();
			hwrStream.Close();

			HttpWebResponse myHttpWebResponse = (HttpWebResponse)hwRequest.GetResponse();
			myHttpWebResponse.Cookies = cc.GetCookies(hwRequest.RequestUri);
			Stream myResponseStream = myHttpWebResponse.GetResponseStream();
			StreamReader myStreamReader = new StreamReader(myResponseStream, eEncoding);
			outdata = myStreamReader.ReadToEnd();
			myStreamReader.Close();
			myResponseStream.Close();
			return outdata;
		}

		/// <summary>
		/// 以默认编码 UTF8 发送请求到一 Url
		/// </summary>
		/// <param name="Url"></param>
		/// <param name="inData">内容</param>
		/// <param name="Method">GET 或 POST</param>
		/// <param name="Referer">来源页</param>
		/// <returns></returns>
		public string Request(string Url, string inData, string Method, string Referer = "")
		{
			return Request(Encoding.UTF8, Url, inData, Method, new CookieContainer(), "application/x-www-form-urlencoded", Referer);
		}

		/// <summary>
		/// 以指定编码发送请求到一 Url
		/// </summary>
		/// <param name="eEncoding">编码</param>
		/// <param name="Url"></param>
		/// <param name="inData">内容</param>
		/// <param name="Method">GET 或 POST</param>
		/// <param name="Referer">来源页</param>
		/// <returns></returns>
		public string Request(Encoding eEncoding, string Url, string inData, string Method, string Referer = "")
		{
			return Request(eEncoding, Url, inData, Method, new CookieContainer(), "application/x-www-form-urlencoded", Referer);
		}

		/// <summary>
		/// 下载文件块(迅雷每块终点均为文件结尾)
		/// </summary>
		/// <param name="FullFileName">本地文件全名</param>
		/// <param name="FileCache">带分块缓存的本地文件</param>
		/// <param name="idx">块编号</param>
		public void DownFileSection(string FullFileName, Apq.IO.FileCache FileCache, int idx = 0)
		{
			Apq.IO.FileSection FileSection = FileCache.FileSections[idx];

			System.Net.WebRequest reqHttp = System.Net.WebRequest.Create(FileSection.FullFileName);
			WebRequestHelper.AddRange(reqHttp, FileCache.FileSecCaches[idx].PosBegin);// 设置起点

			// 获取服务器输出流
			WebResponse response = reqHttp.GetResponse();
			Stream httpStream = response.GetResponseStream();

			if (_ReadSize > FileSection.TotalSize)
			{
				_ReadSize = (int)FileSection.TotalSize;
			}
			byte[] buffer = new byte[_ReadSize];//接收数据缓冲区
			int readCount = _ReadSize;//初始为_ReadSize是为了进入第一次循环
			long c = 0;//本块已下载量

			while (true)
			{
				if (c >= FileSection.SecSize)// 本块已结束
				{
					FileCache.FileSecCaches[idx].FlushToStream();
					break;
				}

				readCount = httpStream.Read(buffer, 0, _ReadSize);
				FileCache.FileSecCaches[idx].WriteRange(buffer, 0, readCount);
				c += readCount;

				Apq.JinDu.JinDu e = new JinDu.JinDu(FileSection.SecSize, c, FileSection.SubNo, FileSection.FullFileName);
				OnJinDuChanged(e);
			}

			httpStream.Close();
			response.Close();
		}

		/// <summary>
		/// 下载文件,不支持分块,不支持断点续传
		/// </summary>
		/// <param name="FileSection">远程文件(分块信息中的起点必须为0,否则什么都不干)</param>
		/// <param name="FullFileName">本地文件全名</param>
		public void DownFile(string FullFileName, Apq.IO.FileSection FileSection)
		{
			if (FileSection.PosBegin == 0)
			{
				WebClient x = new WebClient();
				x.DownloadProgressChanged += new DownloadProgressChangedEventHandler(x_DownloadProgressChanged);
				x.DownloadFileAsync(new Uri(FileSection.FullFileName), FullFileName, FileSection);
			}
		}

		void x_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
		{
			Apq.IO.FileSection FileSection = e.UserState as Apq.IO.FileSection;

			Apq.JinDu.JinDu _e = new JinDu.JinDu(e.TotalBytesToReceive, e.BytesReceived, FileSection.SubNo, FileSection.FullFileName);
			OnJinDuChanged(_e);

			if (e.BytesReceived >= e.TotalBytesToReceive && FileSection.ManualResetEvent != null)
			{
				FileSection.ManualResetEvent.Set();
			}
		}

		/// <summary>
		/// 获取指定文件大小
		/// </summary>
		public long GetFileSize(string Url)
		{
			System.Net.HttpWebRequest reqHttp = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(Url);

			// 获取服务器输出流
			HttpWebResponse response = (HttpWebResponse)reqHttp.GetResponse();
			return response.ContentLength;
		}

		#region 事件
		/// <summary>
		/// 下载进度变化事件
		/// </summary>
		public event Apq.JinDu.JinDuChangedHandler JinDuChanged;

		/// <summary>
		/// 引发进度改变事件
		/// </summary>
		protected void OnJinDuChanged(Apq.JinDu.JinDu e)
		{
			if (JinDuChanged != null)
			{
				JinDuChanged(this, e);
			}
		}
		#endregion
	}
}
